Medium 清新閱讀版
:連結
前一天我們演練了 API 相關的基本測試方式,今天我們來看一下資料庫的測試方式吧!
Factory
& UserRepository
在開始實作資料庫測試之前,先與大家介紹 Factory
這個東西。
Factory
是個 Laravel 的 ORM:Eloquent 提供的功能,它可以讓我們用很簡單的方式,去準備測試資料,在 Laravel 初始化後,預設已經幫我們準備好了一個 UserFactory
(而之所以 Laravel 官方預先準備了這個 Factory
,可能是因為最基本預設的資料表,就是 users
),慣例上會將 Factory
檔放在 database/factories
這個資料夾下,並且會命名為 XxxFactory
,其中 Xxx
是資源名稱:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*
* @return static
*/
public function unverified()
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
Factory
有2種主要的使用方式,第1種是會在資料表實際建立資料,並且回應 Eloquent Enity,用法如下:
$user = User::facotry()->create();
以上程式碼會立即在資料庫建立 User資料,其中 name
、email
會使用 fake()
來隨機建立假值,email_verified_at
會用當下時間,remember_token
則會是一個隨機產生的 10 個字的字串。
另1種方式,則不會在資料庫建立資料,但仍會回應 Eloquent Enity,用法如下:
$user = User::facotry()->make();
不過要注意,用 make()
來建立資料實體,其 id
欄位值會是空值喔(因為沒有實際在資料庫建立資料)。
此外,也可以在建立資料時,指定你想要的欄位值:
$user = User::facotry()->create(['name' => 'william']);
以上就是 Factory
的相關介紹,當然其實還有更多有趣的技術細節值得探討,像是神秘的 fake()
,不過這讓我們在之後的文章再來探討吧!
理解了準備資料的方式後,讓我們來看看今天要測試的對象,以下是針對 User
這個資源,所實作的資料操作類別 UserRepository
:
<?php
namespace App\Repositories;
use App\Models\User;
class UserRepository
{
protected $model;
public function __construct(User $model)
{
$this->model = $model;
}
// 依給予的輸入資料,於資料庫中建立 User 資料
public function createUser(array $data)
{
return $this->model::create($data);
}
// 更新指定 ID 之 User 資料之姓名值
public function updateUserNameById($userId, string $name)
{
$user = $this->getUserById($userId);
if (empty($user)) {
return false;
}
$user->name = $name;
return $user->save();
}
// 刪除指定 ID 之 User 資料
public function deleteUserById($userId)
{
$user = $this->getUserById($userId);
if (empty($user)) {
return false;
}
return $user->delete();
}
// 讀取指定 ID 之 User 資料
public function getUserById($userId)
{
return $this->model::find($userId);
}
}
以上程式碼實作了關於 User
這個資源的 CRUD 4種操作,接著就來寫測試吧!
首先是建立資料功能的測試,請看以下程式碼:
namespace Tests\Feature;
use App\Repositories\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserRepositoryTest extends TestCase
{
use RefreshDatabase;
/**
* Example for user creating
* @return void
*/
public function testUserCreating()
{
$repository = app(UserRepository::class);
$repository->createUser([
'name' => 'test_name',
'email' => 'test@test.test',
'password' => 'password',
]);
$this->assertDatabaseHas('users', [
'name' => 'test_name',
'email' => 'test@test.test',
'password' => 'password',
]);
}
}
以上程式碼,會呼叫 createUser()
,並在呼叫之後,驗證資料庫中是否存有期望中的資料。
namespace Tests\Feature;
use App\Repositories\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserRepositoryTest extends TestCase
{
use RefreshDatabase;
/**
* Example for user reading
* @return void
*/
public function testUserReading()
{
$user = User::factory()->create();
$repository = app(UserRepository::class);
$userGot = $repository->getUserById($user->id);
$this->assertEquals($user->id, $userGot->id);
}
}
以上程式碼,會先建立假資料 $user
,之後呼叫 getUserById()
,並在呼叫之後,驗證取得的資料之 ID 是否如預期。
namespace Tests\Feature;
use App\Repositories\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserRepositoryTest extends TestCase
{
use RefreshDatabase;
/**
* Example for user updating
* @return void
*/
public function testUserUpdating()
{
$user = User::factory()->create([
'name' => 'test_name',
'email' => 'test@test.test',
'password' => 'password',
]);
$repository = app(UserRepository::class);
$repository->updateUserNameById($user->id, 'name_2');
$this->assertDatabaseHas('users', [
'name' => 'name_2',
]);
}
}
以上程式碼,會先建立假資料 $user
,之後呼叫 updateUserNameById()
,並在呼叫之後,驗證資料是否如期更新。
namespace Tests\Feature;
use App\Repositories\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UserRepositoryTest extends TestCase
{
use RefreshDatabase;
/**
* Example for user deletion
* @return void
*/
public function testUserDeletion()
{
$user = User::factory()->create([
'name' => 'test_name',
'email' => 'test@test.test',
'password' => 'password',
]);
$userId = $user->id;
$repository = app(UserRepository::class);
$repository->deleteUserById($user->id);
$this->assertDatabaseMissing('users', [
'id' => $userId,
]);
}
}
以上程式碼,會先建立假資料 $user
,之後呼叫 deleteUseryId()
,並在呼叫之後,驗證資料是否如預期地刪除。
以上就是今天的資料庫測試介紹。
明天來為大家介紹與自動化測試相關的 Traits。